//
//  EMSCharacterDataController.m
//  EVE Mac Suite
//
//  Created by Vadim Lozko on 3/28/09.
//  Copyright 2009 __Vadim__CompanyName__. All rights reserved.
//

#import "EMSCharacterDataController.h"
#import "EMSCharacterViewController.h"
#import "EMSGeneralUtils.h"
#import "EMSSkillTrainingInfo.h"
#import "EVEAPIDownloaderRequest.h"
#import "EVEAPICoreDataController.h"
#import "EVEAPICharacterSheet.h"
#import "EVEAPISkillQueue.h"
#import "EVEAPIImageDownloader.h"
#import "EVECDCharacter.h"
#import "EVECDSkill.h"
#import "EVECDLearnedGroup.h"
#import "EVECDLearnedSkill.h"

@implementation EMSCharacterDataController

@synthesize delegate;
@synthesize managedObjectCharacter;
@synthesize currentSkillInTraining;
@synthesize skillInTrainingName;
@synthesize timeToFinishTraining;
@synthesize trainingFinishDate;
@synthesize displayInfo;
@synthesize updating;

-(id)initWithCharacterInfo:(NSDictionary*)charInfo
{
	if(self = [super init])
	{
		characterInfo = [charInfo retain];
		self.displayInfo = [NSDictionary dictionary];
		NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
		[defaultCenter addObserver:self 
						  selector:@selector(characterSheetUpdateDidFinish:) 
							  name:CHARACTER_SHEET_API_TYPE 
							object:nil];
		[defaultCenter addObserver:self 
						  selector:@selector(skillQueueUpdateDidFinish:) 
							  name:CHARACTER_SKILL_QUEUE_API_TYPE
							object:nil];
		[defaultCenter addObserver:self 
						  selector:@selector(stopUpdatingCurrentSkillInTraining) 
							  name:WILL_UPDATE_LEARNED_SKILLS_NOTIFICATION_NAME 
							object:nil];
	}
	return self;
}

-(void)dealloc
{
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[skillInTrainingName release];
	[timeToFinishTraining release];
	[trainingFinishDate release];
	if(characterInfo){[characterInfo release];}
	if(characterSheet)
	{
		[characterSheet invalidateTimers];
		[characterSheet release];
	}
	self.currentSkillInTraining = nil;
	self.displayInfo = nil;
	if(skillPointsUpdateTimer)
	{
		[skillPointsUpdateTimer invalidate];
	}
	if(updateReferenceDate)
	{
		[updateReferenceDate release];
	}
	[super dealloc];
}

-(NSString*)charName
{
	return [characterInfo objectForKey:CHAR_INFO_DICT_NAME];
}

-(NSManagedObjectContext*)managedObjectContext
{
	return EVECDContext;
}

-(NSDictionary*)characterInfo
{
	return characterInfo;
}

-(void)update
{
	characterSheet = [[EVEAPICharacterSheet alloc] initWithCharacterInfo:characterInfo];
	characterSheet.delegate = self;
	[characterSheet forceUpdate];
	self.updating = YES;
}

-(void)forceUpdate
{
	[characterSheet forceUpdate];
	self.updating = YES;
}

-(void)downloadRequestDidFinishForImageData:(NSData*)data
{
	managedObjectCharacter.image = data;
	[[EVEAPICoreDataController coreDataController] saveData];
}



-(void)characterSheetUpdateDidFinish:(NSNotification*)notfication
{
		BOOL success = [[[notfication userInfo] objectForKey:NOTIFICATION_SUCCESS_UPDATE_KEY] boolValue];
	NSString* notificationCharName = [[notfication userInfo] objectForKey:CHAR_INFO_DICT_NAME];
	if([notificationCharName isEqualToString:[self charName]])
	{
		managedObjectCharacter = characterSheet.managedObjectCharacter;

		if(success && managedObjectCharacter)
		{
			NSData* imageData = managedObjectCharacter.image;
			if(!imageData)
			{
				imageDownloader = [[EVEAPIImageDownloader alloc] init];
				imageDownloader.delegate = self;
				NSMutableDictionary* imageInfoDict = [characterInfo mutableCopy];
				[imageInfoDict setObject:@"256" forKey:CHAR_INFO_DICT_PIXELSIZE];
				[imageDownloader performAPIDownloadRequest:[EVEAPIDownloaderRequest requestWithType:@"Image" 
																							   info:imageInfoDict
																							handler:self]];
				[imageInfoDict release];
			}
			if(!skillQueue)
			{
				skillQueue = [[EVEAPISkillQueue alloc] initWithCharacterInfo:characterInfo];
			}
			skillQueue.delegate = self;
			[skillQueue forceUpdate];
		} else {
			[EMSGeneralUtils showNoInternetConnectionAlertWithMessage:[self charName]];
			self.updating = NO;
			if(skillPointsUpdateTimer)
			{
				[skillPointsUpdateTimer invalidate];
				skillPointsUpdateTimer = nil;
			}
			self.displayInfo = [NSDictionary dictionaryWithObject:managedObjectCharacter.objectID forKey:DISPLAY_INFO_DICT_CHARACTER];
		}
		nextUpdateUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 
																 target:self 
															   selector:@selector(refreshUpdateTimeValue) 
															   userInfo:nil 
																repeats:YES];
		if([delegate respondsToSelector:@selector(characterDataController:dataDidLoad:)])
		{
			[delegate characterDataController:self dataDidLoad:YES];
		}
		
	}
}

 -(void)skillQueueUpdateDidFinish:(NSNotification*)notification
{
	NSDictionary* userInfo = [notification userInfo];
	if([[userInfo objectForKey:NOTIFICATION_SUCCESS_UPDATE_KEY] boolValue] && [notification object] &&
	   [[userInfo objectForKey:CHAR_INFO_DICT_NAME] isEqualToString:[self charName]])
	{
		if(updateReferenceDate)
		{
			[updateReferenceDate release];
		}
		self.currentSkillInTraining = [(EVECDLearnedSkill*)[notification object] retain];
		updateReferenceDate = [self.currentSkillInTraining.learningStart copy];
		startSkillPoints = self.currentSkillInTraining.skillPointsLearned.intValue;
		double secondsPerSkillPoint = 1 / [EMSSkillTrainingInfo skillPointsPerSecondForSkill:self.currentSkillInTraining];
		//Set the skill training name string
		int level = self.currentSkillInTraining.level.intValue;
		self.skillInTrainingName = [NSString stringWithFormat:@"%@ %@",
									self.currentSkillInTraining.skill.name,
									[EMSSkillTrainingInfo romanNumeralFrontInt:(level + 1)]];
		
		//Set the skill training finish date string
		NSTimeInterval totalSecondsToNextLevel = [EMSSkillTrainingInfo trainingTimeToNextLevelForLearnedSkill:self.currentSkillInTraining];

		NSDate* finishDate = [NSDate dateWithTimeIntervalSinceNow:totalSecondsToNextLevel];
		NSString* selectedTimeZoneString = [[NSUserDefaults standardUserDefaults] stringForKey:@"selectedTimeZone"];
		NSTimeZone* timeZone;
		if([selectedTimeZoneString isEqualToString:@"Local Time"])
		{
			timeZone = [NSTimeZone localTimeZone];
		} else {
			timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
		}
		self.timeToFinishTraining = [finishDate descriptionWithCalendarFormat:@"%A, %B %e at %I:%M %p"
																	 timeZone:timeZone
																	   locale:nil];
		if(skillPointsUpdateTimer)
		{
			[skillPointsUpdateTimer invalidate];
		}
		skillPointsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:secondsPerSkillPoint 
																  target:self 
																selector:@selector(updateCurrentSkillInTraining) 
																userInfo:nil 
																 repeats:YES];
		self.updating = NO;
		[skillPointsUpdateTimer fire];
		
	} else if([[userInfo objectForKey:CHAR_INFO_DICT_NAME] isEqualToString:[self charName]]){
		self.currentSkillInTraining = nil;
		if(skillPointsUpdateTimer)
		{
			[skillPointsUpdateTimer invalidate];
			skillPointsUpdateTimer = nil;
		}
		self.displayInfo = [NSDictionary dictionaryWithObject:managedObjectCharacter.objectID forKey:DISPLAY_INFO_DICT_CHARACTER];
		self.updating = NO;
	}
	
}

-(void)stopUpdatingCurrentSkillInTraining
{
	[skillPointsUpdateTimer invalidate];
	skillPointsUpdateTimer = nil;
	self.updating = NO;
}

-(void)updateCurrentSkillInTraining
{
	//Update the managed object
	double skillPointsPerSecond = [EMSSkillTrainingInfo skillPointsPerSecondForSkill:self.currentSkillInTraining];
	NSTimeInterval timeSinceReference = [[NSDate date] timeIntervalSinceDate:updateReferenceDate];
	int accruedPoints = skillPointsPerSecond * timeSinceReference;
	int skillPoints = startSkillPoints + accruedPoints;
	int level = self.currentSkillInTraining.level.intValue;
	int rank = self.currentSkillInTraining.skill.rank.intValue;
	int pointsToNextLevel = [EMSSkillTrainingInfo skillPointsRequiredForLevel:(level + 1) rank:rank];
	NSDate* learningStart = [NSDate date];
	//[EVECDContext lock];
	[currentSkillInTraining willChangeValueForKey:@"displayInfo"];
	[currentSkillInTraining willChangeValueForKey:@"level"];
	[managedObjectCharacter willChangeValueForKey:@"queuedSkills"];
	[self willChangeValueForKey:@"displayInfo"];				
	[currentSkillInTraining.partOfLearnedGroup willChangeValueForKey:@"skillPointsLearned"];
	[currentSkillInTraining.partOfLearnedGroup willChangeValueForKey:@"displayInfo"];
	self.currentSkillInTraining.skillPointsLearned = [NSNumber numberWithInt:skillPoints];
	[currentSkillInTraining didChangeValueForKey:@"displayInfo"];
	[currentSkillInTraining didChangeValueForKey:@"level"];
	[managedObjectCharacter didChangeValueForKey:@"queuedSkills"];
	[self didChangeValueForKey:@"displayInfo"];
	[currentSkillInTraining.partOfLearnedGroup didChangeValueForKey:@"skillPointsLearned"];
	[currentSkillInTraining.partOfLearnedGroup didChangeValueForKey:@"displayInfo"];
	currentSkillInTraining.learningStart = learningStart;
	//[EVECDContext unlock];
	//Set the time left string
	NSTimeInterval totalSecondsToNextLevel = [EMSSkillTrainingInfo trainingTimeToNextLevelForLearnedSkill:self.currentSkillInTraining];
	HumanNotationTime time = [EMSSkillTrainingInfo humanNotationTimeFromTimeInterval:totalSecondsToNextLevel];

	NSString* dayString = (time.days == 1) ? @"Day" : @"Days";
	NSString* hourString = (time.hours == 1) ? @"Hour" : @"Hours";
	NSString* minuteString = (time.minutes == 1) ? @"Minute" : @"Minutes";
	NSString* secondString = (time.seconds == 1) ? @"Second" : @"Seconds";
	self.trainingFinishDate = [NSString stringWithFormat:@"%i %@, %i %@, %i %@, %i %@", 
							   time.days, dayString, time.hours, hourString, time.minutes, minuteString, time.seconds, secondString];
	NSString* sumString = [NSString stringWithFormat:@"%iD %iH %iM %iS", time.days, time.hours, time.minutes, time.seconds];
	self.displayInfo = [NSDictionary dictionaryWithObjectsAndKeys:managedObjectCharacter.objectID, DISPLAY_INFO_DICT_CHARACTER,
						sumString, DISPLAY_INFO_DICT_SKILL_IN_TRAINING_TIME_TO_TRAIN,
						skillInTrainingName, DISPLAY_INFO_DICT_SKILL_IN_TRAINING_NAME, nil];
	if(skillPoints >= pointsToNextLevel)
	{
		[skillPointsUpdateTimer invalidate];
		skillPointsUpdateTimer = nil;
		[[NSNotificationCenter defaultCenter] postNotificationName:SKILL_IN_TRAINING_DID_FINISH_NOTIFICATION object:self.currentSkillInTraining];
		[self performSelector:@selector(forceUpdate) withObject:nil afterDelay:5.0];
	}
}

-(void)refreshUpdateTimeValue
{
	[self willChangeValueForKey:@"updateTime"];
	[self didChangeValueForKey:@"updateTime"];
}

-(NSDate*)updateTime
{
	return [[characterSheet updateTimer] fireDate];
}

-(void)invalidateTimers
{
	[self stopUpdatingCurrentSkillInTraining];
	if(nextUpdateUpdateTimer)
	{
		[nextUpdateUpdateTimer invalidate];
		nextUpdateUpdateTimer = nil;
	}
}

@end

